﻿using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Net.Cache;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;

namespace OnHook.Common.Extension
{
    /// <summary>
    /// HttpRequest扩展方法
    /// </summary>
    public static class HttpRequestExtension
    {
        #region 设置请求的属性

        /// <summary>
        /// 设置Method
        /// </summary>
        /// <param name="request"></param>
        /// <param name="method"></param>
        /// <returns></returns>
        public static HttpWebRequest SetMethod(this HttpWebRequest request, string method)
        {
            request.Method = method;
            return request;
        }
        /// <summary>
        /// 设置超时时间
        /// </summary>
        /// <param name="request"></param>
        /// <param name="timeoutMilliseconds"></param>
        /// <returns></returns>
        public static HttpWebRequest SetTimeout(this HttpWebRequest request, int timeoutMilliseconds)
        {
            request.Timeout = timeoutMilliseconds;
            return request;
        }

        /// <summary>
        /// 设置浏览器头
        /// </summary>
        /// <param name="request"></param>
        /// <param name="userAgent">
        /// 谷歌： Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36
        /// 火狐：Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:70.0) Gecko/20100101 Firefox/70.0
        /// </param>
        /// <returns></returns>
        public static HttpWebRequest SetUserAgent(this HttpWebRequest request, string userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36")
        {
            request.UserAgent = userAgent;
            return request;
        }

        /// <summary>
        /// 设置代理
        /// </summary>
        /// <param name="request"></param>
        /// <param name="host"></param>
        /// <param name="port"></param>
        /// <returns></returns>
        public static HttpWebRequest SetProxy(this HttpWebRequest request, string host = "", int? port = null)
        {
            if (host.IsEmpty()) return request;
            WebProxy proxy = port.HasValue ? new WebProxy(host, port.Value) : new WebProxy(new Uri(host));
            request.Proxy = proxy;
            return request;
        }

        /// <summary>
        /// 设置请求类型
        /// </summary>
        /// <param name="request"></param>
        /// <param name="contentType">
        /// form表单： application/x-www-form-urlencoded
        /// json： application/json
        /// </param>
        /// <returns></returns>
        public static HttpWebRequest SetContentType(this HttpWebRequest request, string contentType = "application/x-www-form-urlencoded")
        {
            request.ContentType = contentType;
            return request;
        }

        /// <summary>
        /// 是否允许自动跳转
        /// </summary>
        /// <param name="request"></param>
        /// <param name="flag"></param>
        /// <returns></returns>
        public static HttpWebRequest SetAllowAutoRedirect(this HttpWebRequest request, bool flag = true)
        {
            request.AllowAutoRedirect = flag;
            return request;
        }

        /// <summary>
        /// 设置请求将跟随的重定向的最大数目
        /// </summary>
        /// <param name="request"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public static HttpWebRequest SetMaximumAutomaticRedirections(this HttpWebRequest request, int count = 50)
        {
            request.MaximumAutomaticRedirections = count;
            return request;
        }

        /// <summary>
        /// HTTP 标头的值。 默认值为 null。
        /// </summary>
        /// <param name="request"></param>
        /// <param name="accept"></param>
        /// <returns></returns>
        public static HttpWebRequest SetAccept(this HttpWebRequest request, string accept = "")
        {
            request.Accept = accept;
            return request;
        }

        /// <summary>
        /// 设置请求缓存策略
        /// </summary>
        /// <param name="request"></param>
        /// <param name="policy"></param>
        /// <returns></returns>
        public static HttpWebRequest SetCachePolicy(this HttpWebRequest request, RequestCachePolicy policy = null!)
        {
            request.CachePolicy = policy;
            return request;
        }

        /// <summary>
        /// 设置Cookie
        /// </summary>
        /// <param name="request"></param>
        /// <param name="cookies"></param>
        /// <returns></returns>
        public static HttpWebRequest SetCookie(this HttpWebRequest request, params Cookie[] cookies)
        {
            if (cookies.IsNotEmpty())
            {
                cookies.Foreach(item =>
                {
                    request.CookieContainer = new CookieContainer();
                    request.CookieContainer.Add(item);
                });
            }
            return request;
        }

        /// <summary>
        /// 设置请求头
        /// </summary>
        /// <param name="request"></param>
        /// <param name="headerName"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static HttpWebRequest SetHeader(this HttpWebRequest request, string headerName, string value)
        {
            if (!UNCHANGEHEADS.Contains(headerName))
            {
                request.Headers.Add(headerName, value);
            }
            else
            {
                SetHeaderValue(request, headerName, value);
            }
            return request;
        }

        /// <summary>
        /// 设置Header
        /// </summary>
        /// <param name="request"></param>
        /// <param name="headerDict"></param>
        /// <returns></returns>
        public static HttpWebRequest SetHeader(this HttpWebRequest request, Dictionary<string, string> headerDict)
        {
            if (headerDict.IsNotEmpty())
            {
                headerDict.Foreach(item => request.SetHeader(item.Key, item.Value));
            }
            return request;
        }

        public static HttpWebRequest SetCerts(this HttpWebRequest request, string certPath)
        {
            if (certPath.IsNotEmpty())
            {
                X509Certificate2 cert = new X509Certificate2(certPath);
                request.ClientCertificates.Add(cert);
            }
            return request;
        }

        private static void SetHeaderValue(HttpWebRequest request, string header, string value)
        {
            #region  设置http头
            switch (header)
            {
                case "Accept":
                    {
                        request.Accept = value;
                        break;
                    }
                case "Host":
                    {
                        request.Host = value;
                        break;
                    }
                case "Connection":
                    {
                        if (value == "keep-alive")
                        {
                            request.KeepAlive = true;
                        }
                        else
                        {
                            request.KeepAlive = false;//just test
                        }
                        break;
                    }
                case "Content-Type":
                    {
                        request.ContentType = value;
                        break;
                    }

                case "User-Agent":
                    {
                        request.UserAgent = value;
                        break;
                    }
                case "Referer":
                    {
                        request.Referer = value;
                        break;
                    }

                case "Content-Length":
                    {
                        request.ContentLength = Convert.ToInt64(value);
                        break;
                    }
                case "Expect":
                    {
                        request.Expect = value;
                        break;
                    }
                case "If-Modified-Since":
                    {
                        request.IfModifiedSince = Convert.ToDateTime(value);
                        break;
                    }
                default:
                    break;
            }
            #endregion
        }



        #endregion

        #region 设置请求数据

        /// <summary>
        /// 
        /// </summary>
        /// <param name="request"></param>
        /// <param name="requestData"></param>
        /// <param name="encoding"></param>
        /// <returns></returns>
        public static HttpWebRequest SetBodyData(this HttpWebRequest request, string requestData, Dictionary<string, byte[]> files, Encoding encoding)
        {
            if (requestData.IsEmpty())
                return request;
            var bytes = encoding.GetBytes(requestData);
            using (var stream = request.GetRequestStream())
            {
                stream.Write(bytes, 0, bytes.Length);

                #region 写入文件
                if (files != null && files.Count > 0)
                {
                    string boundary = DateTime.Now.Ticks.ToString("X"); // 随机分隔线
                    request.ContentType += ("boundary=" + boundary);
                    byte[] itemBoundaryBytes = Encoding.UTF8.GetBytes("\r\n--" + boundary + "\r\n");
                    byte[] endBoundaryBytes = Encoding.UTF8.GetBytes("\r\n--" + boundary + "--\r\n");

                    var keys = files.Keys;

                    foreach (var key in keys)
                    {
                        string fileName = key;
                        if (Path.GetExtension(fileName).IsEmpty())
                        {
                            fileName += ".png";
                        }
                        StringBuilder sbHeader = new StringBuilder(string.Format("Content-Disposition:form-data;name=\"{0}\";filename=\"{1}\"\r\nContent-Type:application/octet-stream\r\n\r\n", "file_object", fileName));
                        byte[] postHeaderBytes = Encoding.UTF8.GetBytes(sbHeader.ToString());

                        byte[] bArr = files[key];
                        stream.Write(postHeaderBytes, 0, postHeaderBytes.Length);
                        stream.Write(bArr, 0, bArr.Length);

                        stream.Write(itemBoundaryBytes, 0, itemBoundaryBytes.Length);
                    }
                    stream.Write(endBoundaryBytes, 0, endBoundaryBytes.Length); //结束标志 
                }
                #endregion
            }
            return request;
        }

        /// <summary>
        /// 设置请求内容
        /// </summary>
        /// <param name="request"></param>
        /// <param name="requestData"></param>
        /// <returns></returns>
        public static HttpWebRequest SetBodyData(this HttpWebRequest request, string requestData, Dictionary<string, byte[]> files = null!)
        {
            return request.SetBodyData(requestData, files, Encoding.UTF8);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="request"></param>
        /// <param name="data"></param>
        /// <param name="encoding"></param>
        /// <returns></returns>
        public static HttpWebRequest SetBodyData<T>(this HttpWebRequest request, T data, Encoding encoding)
        {
            Type type = typeof(T);
            if (type.IsValueType)
            {
                return request.SetBodyData(data?.ToString(), encoding);
            }
            else
            {
                return request.SetBodyData(data?.ToJson(), encoding);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="request"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        public static HttpWebRequest SetBodyData<T>(this HttpWebRequest request, T data)
        {
            return request.SetBodyData(data, Encoding.UTF8);
        }

        public static HttpWebRequest WriteFormData(this HttpWebRequest request,string name,string content, out Stream stream, string boundary = "", string contentDisposition= "form-data",string contentType = "", Encoding encoding = null!)
        {
            if (encoding.IsNull()) encoding = Encoding.UTF8;
            if (boundary.IsEmpty()) boundary = DateTime.Now.Ticks.ToString();
            byte[] itemBoundaryBytes = encoding.GetBytes("--" + boundary + "\r\n");
            string header = $"Content-Disposition: {contentDisposition}; name=\"{name}\";\r\nContent-Type: {contentType}\r\n";
            stream = request.GetRequestStream();
            stream.Write(itemBoundaryBytes);
            stream.Write(encoding.GetBytes(header));
            stream.Write(encoding.GetBytes("\r\n"));
            stream.Write(encoding.GetBytes(content));
            stream.Write(encoding.GetBytes("\r\n"));
            return request;
        }

        public static HttpWebRequest WriteFormData(this HttpWebRequest request, string name, string content, Stream stream, string boundary = "", string contentDisposition = "form-data", string contentType = "", Encoding encoding = null!)
        {
            if (encoding.IsNull()) encoding = Encoding.UTF8;
            if (boundary.IsEmpty()) boundary = DateTime.Now.Ticks.ToString();
            byte[] itemBoundaryBytes = encoding.GetBytes("--" + boundary + "\r\n");
            string header = $"Content-Disposition: {contentDisposition}; name=\"{name}\";\r\nContent-Type: {contentType};\r\n";
            if (stream.IsNull()) stream = request.GetRequestStream();
            stream = request.GetRequestStream();
            stream.Write(itemBoundaryBytes);
            stream.Write(encoding.GetBytes(header));
            stream.Write(encoding.GetBytes("\r\n"));
            stream.Write(encoding.GetBytes(content));
            stream.Write(encoding.GetBytes("\r\n"));
            //stream.Write(endBoundaryBytes);
            return request;
        }

        public static HttpWebRequest WriteFormFile(this HttpWebRequest request,string name,string fileName,byte[] files,out Stream stream,string boundary="", string contentDisposition = "form-data", string contentType = "", Encoding encoding = null!)
        {
            if (encoding.IsNull()) encoding = Encoding.UTF8;
            if (boundary.IsEmpty()) boundary = DateTime.Now.Ticks.ToString();
            byte[] itemBoundaryBytes = encoding.GetBytes("--" + boundary + "\r\n");
            string header = $"Content-Disposition: {contentDisposition}; name=\"{name}\";filename=\"{fileName};\"\r\nContent-Type: {contentType}\r\n";
            stream = request.GetRequestStream();
            stream.Write(itemBoundaryBytes);
            stream.Write(encoding.GetBytes(header));
            stream.Write(encoding.GetBytes("\r\n"));
            stream.Write(files);
            stream.Write(encoding.GetBytes("\r\n"));
            //stream.Write(endBoundaryBytes);
            return request;

        }

        public static HttpWebRequest WriteFormFile(this HttpWebRequest request, string name, string fileName, byte[] files, Stream stream, string boundary = "", string contentDisposition = "form-data", string contentType = "", Encoding encoding = null!)
        {
            if (encoding.IsNull()) encoding = Encoding.UTF8;
            if (boundary.IsEmpty()) boundary = DateTime.Now.Ticks.ToString();
            byte[] itemBoundaryBytes = encoding.GetBytes("--" + boundary + "\r\n");
            string header = $"Content-Disposition: {contentDisposition}; name=\"{name}\";filename=\"{fileName}\";\r\nContent-Type: {contentType}\r\n";
            if(stream.IsNull()) stream = request.GetRequestStream();
            stream.Write(itemBoundaryBytes);
            stream.Write(encoding.GetBytes(header));
            stream.Write(encoding.GetBytes("\r\n"));
            stream.Write(files);
            //stream.Write(encoding.GetBytes("\r\n"));
            //stream.Write(endBoundaryBytes);
            return request;

        }

        public static HttpWebRequest WriteEnd(this HttpWebRequest request,Stream stream,string boundary, Encoding encoding = null!)
        {
            if (encoding.IsNull()) encoding = Encoding.UTF8;
            if (stream.IsNull()) stream = request.GetRequestStream();
            byte[] endBoundaryBytes = encoding.GetBytes("\r\n--" + boundary+"\r\n");
            stream.Write(endBoundaryBytes);
            return request;

        }
        #endregion

        #region 请求头
        static readonly HashSet<String> UNCHANGEHEADS = new HashSet<string>();
        static HttpRequestExtension()
        {
            UNCHANGEHEADS.Add("Host");
            UNCHANGEHEADS.Add("Connection");
            UNCHANGEHEADS.Add("User-Agent");
            UNCHANGEHEADS.Add("Referer");
            UNCHANGEHEADS.Add("Range");
            UNCHANGEHEADS.Add("Content-Type");
            UNCHANGEHEADS.Add("Content-Length");
            UNCHANGEHEADS.Add("Expect");
            UNCHANGEHEADS.Add("Proxy-Connection");
            UNCHANGEHEADS.Add("If-Modified-Since");
            UNCHANGEHEADS.Add("Keep-alive");
            UNCHANGEHEADS.Add("Accept");
        }
        #endregion

        #region 请求

        #region GET请求

        /// <summary>
        /// 请求并反序列化
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="request"></param>
        /// <param name="encoding">Null未UTF-8</param>
        /// <returns></returns>
        public static T Get<T>(this HttpWebRequest request, Encoding encoding)
        {
            return request.SetMethod("GET").Request<T>(encoding);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="request"></param>
        /// <returns></returns>
        public static T Get<T>(this HttpWebRequest request)
        {
            return request.Get<T>(Encoding.UTF8);
        }
        /// <summary>
        /// GET 请求
        /// </summary>
        /// <param name="request"></param>
        /// <param name="encoding"></param>
        /// <returns></returns>
        public static string Get(this HttpWebRequest request, Encoding encoding)
        {
            return request.SetMethod("GET").Request(encoding);
        }
        /// <summary>
        ///  GET 请求
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public static string Get(this HttpWebRequest request)
        {
            return request.Get(Encoding.UTF8);
        }
        /// <summary>
        /// 读取GET请求的返回流
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public static Stream GetStream(this HttpWebRequest request)
        {
            return request.SetMethod("GET").GetResponseStream();
        }

        /// <summary>
        /// 请求并反序列号（默认UTF-8格式）
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="request"></param>
        /// <param name="encoding">Null未UTF-8</param>
        /// <returns></returns>
        public static async Task<T> GetAsync<T>(this HttpWebRequest request, Encoding encoding)
        {
            return await request.SetMethod("GET").RequestAsync<T>(encoding);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="request"></param>
        /// <returns></returns>
        public static async Task<T> GetAsync<T>(this HttpWebRequest request)
        {
            return await request.GetAsync<T>(Encoding.UTF8);
        }
        /// <summary>
        /// Get请求数据
        /// </summary>
        /// <param name="request"></param>
        /// <param name="encoding">Null未UTF-8</param>
        /// <returns></returns>
        public static async Task<string> GetAsync(this HttpWebRequest request, Encoding encoding)
        {
            return await request.SetMethod("GET").RequestAsync(encoding);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public static async Task<string> GetAsync(this HttpWebRequest request)
        {
            return await request.GetAsync(Encoding.UTF8);
        }
        /// <summary>
        /// 读取GET请求的返回流
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public static async Task<Stream> GetStreamAsync(this HttpWebRequest request)
        {
            return await request.SetMethod("GET").GetResponseStreamAsync();
        }

        #endregion

        #region Request请求

        /// <summary>
        /// 请求并反序列化
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="request"></param>
        /// <returns></returns>
        public static T Request<T>(this HttpWebRequest request)
        {
            return request.Request<T>(Encoding.UTF8);
        }

        /// <summary>
        /// 请求并反序列化（默认未Null，表示使用UTF-8格式）
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="request"></param>
        /// <param name="encoding">Null未UTF-8</param>
        /// <returns></returns>
        public static T Request<T>(this HttpWebRequest request, Encoding encoding)
        {
            T value;
            string strResult = request.Request(encoding);
            value = strResult.ChangeType<T>();
            return value;
        }

        /// <summary>
        /// 请求
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public static string Request(this HttpWebRequest request)
        {
            return request.Request(Encoding.UTF8);
        }

        /// <summary>
        /// 请求
        /// </summary>
        /// <param name="request"></param>
        /// <param name="encoding">Null未UTF-8</param>
        /// <returns></returns>
        public static string Request(this HttpWebRequest request, Encoding encoding)
        {
            string strResult = string.Empty;
            using (var respons = request.GetResponse())
            {
                using StreamReader reader = new StreamReader(respons.GetResponseStream(), encoding);
                strResult = reader.ReadToEnd();
            }

            return strResult;
        }

        /// <summary>
        /// 读取请求流
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public static Stream GetResponseStream(this HttpWebRequest request)
        {
            MemoryStream memory;
            using (HttpWebResponse resp = (HttpWebResponse)request.GetResponse())
            {
                memory = new MemoryStream();
                if (resp.ContentEncoding.IsNotNull() && resp.ContentEncoding.ToLower().Contains("gzip"))
                {
                    using GZipStream stream = new GZipStream(resp.GetResponseStream(), CompressionMode.Decompress);
                    stream.CopyTo(memory);
                }
                else if (resp.ContentEncoding.IsNotNull() && resp.ContentEncoding.ToLower().Contains("deflate"))
                {
                    using DeflateStream stream = new DeflateStream(resp.GetResponseStream(), CompressionMode.Decompress);
                    stream.CopyTo(memory);
                }
                else
                {
                    using Stream stream = resp.GetResponseStream();
                    stream.CopyTo(memory);
                }
            }
            return memory;
        }

        /// <summary>
        /// 请求并反序列化
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="request"></param>
        /// <returns></returns>
        public static async Task<T> RequestAsync<T>(this HttpWebRequest request)
        {
            return await request.RequestAsync<T>(Encoding.UTF8);
        }

        /// <summary>
        /// 请求并反序列化
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="request"></param>
        /// <param name="encoding">Null未UTF-8</param>
        /// <returns></returns>
        public static async Task<T> RequestAsync<T>(this HttpWebRequest request, Encoding encoding)
        {
            T value;
            string strResult = await request.RequestAsync(encoding);
            value = strResult.ChangeType<T>();
            return value;
        }

        /// <summary>
        /// 请求数据
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public static async Task<string> RequestAsync(this HttpWebRequest request)
        {
            return await request.RequestAsync(Encoding.UTF8);
        }

        /// <summary>
        /// 请求数据
        /// </summary>
        /// <param name="request"></param>
        /// <param name="encoding">Null未UTF-8</param>
        /// <returns></returns>
        public static async Task<string> RequestAsync(this HttpWebRequest request, Encoding encoding)
        {
            string strResult = string.Empty;
            using (StreamReader reader = new StreamReader(await request.GetRequestStreamAsync(), encoding))
            {
                strResult = reader.ReadToEnd();
            }
            return strResult;
        }

        /// <summary>
        /// 读取请求流
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public static async Task<Stream> GetResponseStreamAsync(this HttpWebRequest request)
        {
            MemoryStream memory;
            using (HttpWebResponse resp = (HttpWebResponse)(await request.GetResponseAsync()))
            {
                memory = new MemoryStream(); if (resp.ContentEncoding.ToLower().Contains("gzip"))
                {
                    using GZipStream stream = new GZipStream(resp.GetResponseStream(), CompressionMode.Decompress);
                    await stream.CopyToAsync(memory);
                }
                else if (resp.ContentEncoding.ToLower().Contains("deflate"))
                {
                    using DeflateStream stream = new DeflateStream(resp.GetResponseStream(), CompressionMode.Decompress);
                    await stream.CopyToAsync(memory);
                }
                else
                {
                    using Stream stream = resp.GetResponseStream();
                    await stream.CopyToAsync(memory);
                }
            }
            return memory;
        }
        #endregion

        #region POST请求

        /// <summary>
        /// POST请求
        /// </summary>
        /// <param name="request"></param>
        /// <param name="dataString"></param>
        /// <param name="requestEncode"></param>
        /// <param name="responseEncode"></param>
        /// <returns></returns>
        public static string Post(this HttpWebRequest request, string dataString, Dictionary<string, byte[]> files, Encoding requestEncode, Encoding responseEncode)
        {
            request.SetMethod("POST");
            if (dataString.IsNotEmpty())
            {
                request.SetBodyData(dataString, files, requestEncode);
            }
            return request.Request(responseEncode);
        }

        /// <summary>
        /// POST请求
        /// </summary>
        /// <param name="request"></param>
        /// <param name="dataString"></param>
        /// <returns></returns>
        public static string Post(this HttpWebRequest request, string dataString, Dictionary<string, byte[]> files)
        {
            return request.Post(dataString, files, Encoding.UTF8, Encoding.UTF8);
        }

        /// <summary>
        /// POST请求
        /// </summary>
        /// <param name="request"></param>
        /// <param name="dataString"></param>
        /// <param name="requestEncode"></param>
        /// <param name="responseEncode"></param>
        /// <returns></returns>
        public static async Task<string> PostAsync(this HttpWebRequest request, string dataString, Dictionary<string, byte[]> files, Encoding requestEncode, Encoding responseEncode)
        {
            request.SetMethod("POST");
            if (dataString.IsNotEmpty())
            {
                request.SetBodyData(dataString, requestEncode);
            }
            return await request.RequestAsync(responseEncode);
        }


        /// <summary>
        /// POST请求
        /// </summary>
        /// <param name="request"></param>
        /// <param name="dataString"></param>
        /// <returns></returns>
        public static async Task<string> PostAsync(this HttpWebRequest request, string dataString, Dictionary<string, byte[]> files = null!)
        {
            return await request.PostAsync(dataString, files, Encoding.UTF8, Encoding.UTF8);
        }

        /// <summary>
        /// POST请求，结果反序列化
        /// </summary>
        /// <typeparam name="TReturn"></typeparam>
        /// <param name="request"></param>
        /// <param name="dataString"></param>
        /// <param name="requestEncode"></param>
        /// <param name="responseEncode"></param>
        /// <returns></returns>
        public static TReturn Post<TReturn>(this HttpWebRequest request, string dataString, Dictionary<string, byte[]> files, Encoding requestEncode, Encoding responseEncode)
        {
            TReturn value;
            string strResult = request.Post(dataString, files, requestEncode, responseEncode);
            value = strResult.ChangeType<TReturn>();
            return value;
        }

        /// <summary>
        /// POST请求，结果反序列化
        /// </summary>
        /// <typeparam name="TReturn"></typeparam>
        /// <param name="request"></param>
        /// <param name="dataString"></param>
        /// <returns></returns>
        public static TReturn Post<TReturn>(this HttpWebRequest request, string dataString, Dictionary<string, byte[]> files)
        {
            return request.Post<TReturn>(dataString, files, Encoding.UTF8, Encoding.UTF8);
        }

        /// <summary>
        /// POST请求，结果反序列化
        /// </summary>
        /// <typeparam name="TReturn"></typeparam>
        /// <param name="request"></param>
        /// <param name="dataString"></param>
        /// <param name="requestEncode"></param>
        /// <param name="responseEncode"></param>
        /// <returns></returns>
        public static async Task<TReturn> PostAsync<TReturn>(this HttpWebRequest request, string dataString, Dictionary<string, byte[]> files, Encoding requestEncode, Encoding responseEncode)
        {
            TReturn value;
            string strResult = await request.PostAsync(dataString, files, requestEncode, responseEncode);
            value = strResult.ChangeType<TReturn>();
            return value;
        }
        /// <summary>
        /// POST请求，结果反序列化
        /// </summary>
        /// <typeparam name="TReturn"></typeparam>
        /// <param name="request"></param>
        /// <param name="dataString"></param>
        /// <returns></returns>
        public static async Task<TReturn> PostAsync<TReturn>(this HttpWebRequest request, string dataString, Dictionary<string, byte[]> files)
        {
            return await request.PostAsync<TReturn>(dataString, files, Encoding.UTF8, Encoding.UTF8);
        }

        #endregion

        #region POST Form
        /// <summary>
        /// Form表单提交
        /// </summary>
        /// <param name="request"></param>
        /// <param name="postData"></param>
        /// <param name="files"></param>
        /// <param name="respEncode"></param>
        public static string FormPost(this HttpWebRequest request, Dictionary<string, object> postData, Dictionary<string, byte[]> files, Encoding respEncode)
        {
            string boundary = DateTime.Now.Ticks.ToString("X"); // 随机分隔线
            request.ContentType = "multipart/form-data;charset=utf-8;boundary=" + boundary;

            byte[] itemBoundaryBytes = Encoding.UTF8.GetBytes("\r\n--" + boundary + "\r\n");
            byte[] endBoundaryBytes = Encoding.UTF8.GetBytes("\r\n--" + boundary + "--\r\n");

            Stream postStream = request.GetRequestStream();
            postStream.Write(itemBoundaryBytes, 0, itemBoundaryBytes.Length);

            #region 写入Form数据
            if (postData != null && postData.Count > 0)
            {

                var keys = postData.Keys;
                foreach (var key in keys)
                {
                    string strHeader = string.Format("Content-Disposition: form-data; name=\"{0}\"\r\n\r\n", key);
                    byte[] strByte = System.Text.Encoding.UTF8.GetBytes(strHeader);
                    postStream.Write(strByte, 0, strByte.Length);

                    byte[] value = System.Text.Encoding.UTF8.GetBytes(string.Format("{0}", postData[key]));
                    postStream.Write(value, 0, value.Length);

                    postStream.Write(itemBoundaryBytes, 0, itemBoundaryBytes.Length);

                }
            }
            postStream.Write(itemBoundaryBytes, 0, itemBoundaryBytes.Length);
            #endregion

            #region 写入文件
            if (files != null && files.Count > 0)
            {
                var keys = files.Keys;

                foreach (var key in keys)
                {
                    string fileName = key;
                    if (Path.GetExtension(fileName).IsEmpty())
                    {
                        fileName += ".png";
                    }
                    StringBuilder sbHeader = new StringBuilder(string.Format("Content-Disposition:form-data;name=\"{0}\";filename=\"{1}\"\r\nContent-Type:application/octet-stream\r\n\r\n", "file_object", fileName));
                    byte[] postHeaderBytes = Encoding.UTF8.GetBytes(sbHeader.ToString());

                    byte[] bArr = files[key];
                    postStream.Write(postHeaderBytes, 0, postHeaderBytes.Length);
                    postStream.Write(bArr, 0, bArr.Length);

                    postStream.Write(itemBoundaryBytes, 0, itemBoundaryBytes.Length);
                }

            }
            postStream.Write(endBoundaryBytes, 0, endBoundaryBytes.Length); //结束标志 
            #endregion
            return request.Request(respEncode);
        }

        /// <summary>
        /// Form表单提交
        /// </summary>
        /// <typeparam name="TParms"></typeparam>
        /// <typeparam name="TReturn"></typeparam>
        /// <param name="request"></param>
        /// <param name="parms"></param>
        /// <param name="files"></param>
        /// <returns></returns>
        public static TReturn FormPost<TParms, TReturn>(this HttpWebRequest request, TParms parms, Dictionary<string, byte[]> files = null!)
        {
            var dict = parms?.ToDictionary();
            string strResult = request.FormPost(dict!, files, Encoding.UTF8);
            return strResult.ChangeType<TReturn>();
        }

        /// <summary>
        /// Form表单提交
        /// </summary>
        /// <param name="request"></param>
        /// <param name="postData"></param>
        /// <param name="files"></param>
        /// <param name="respEncode"></param>
        /// <returns></returns>
        public static async Task<string> FormPostAsync(this HttpWebRequest request, Dictionary<string, object> postData, Dictionary<string, byte[]> files, Encoding respEncode)
        {
            string boundary = DateTime.Now.Ticks.ToString("X"); // 随机分隔线
            request.ContentType = "multipart/form-data;charset=utf-8;boundary=" + boundary;

            byte[] itemBoundaryBytes = Encoding.UTF8.GetBytes("\r\n--" + boundary + "\r\n");
            byte[] endBoundaryBytes = Encoding.UTF8.GetBytes("\r\n--" + boundary + "--\r\n");

            Stream postStream = request.GetRequestStream();
            postStream.Write(itemBoundaryBytes, 0, itemBoundaryBytes.Length);

            #region 写入Form数据
            if (postData != null && postData.Count > 0)
            {

                var keys = postData.Keys;
                foreach (var key in keys)
                {
                    string strHeader = string.Format("Content-Disposition: form-data; name=\"{0}\"\r\n\r\n", key);
                    byte[] strByte = System.Text.Encoding.UTF8.GetBytes(strHeader);
                    await postStream.WriteAsync(strByte, 0, strByte.Length);

                    byte[] value = System.Text.Encoding.UTF8.GetBytes(string.Format("{0}", postData[key]));
                    await postStream.WriteAsync(value, 0, value.Length);

                    await postStream.WriteAsync(itemBoundaryBytes, 0, itemBoundaryBytes.Length);

                }
            }
            await postStream.WriteAsync(itemBoundaryBytes, 0, itemBoundaryBytes.Length);
            #endregion

            #region 写入文件
            if (files != null && files.Count > 0)
            {
                var keys = files.Keys;

                foreach (var key in keys)
                {
                    string fileName = key;
                    if (Path.GetExtension(fileName).IsEmpty())
                    {
                        fileName += ".png";
                    }
                    StringBuilder sbHeader = new StringBuilder(string.Format("Content-Disposition:form-data;name=\"{0}\";filename=\"{1}\"\r\nContent-Type:application/octet-stream\r\n\r\n", "file_object", fileName));
                    byte[] postHeaderBytes = Encoding.UTF8.GetBytes(sbHeader.ToString());

                    byte[] bArr = files[key];
                    await postStream.WriteAsync(postHeaderBytes, 0, postHeaderBytes.Length);
                    await postStream.WriteAsync(bArr, 0, bArr.Length);

                    await postStream.WriteAsync(itemBoundaryBytes, 0, itemBoundaryBytes.Length);
                }

            }
            await postStream.WriteAsync(endBoundaryBytes, 0, endBoundaryBytes.Length); //结束标志 
            #endregion

            return await request.RequestAsync(respEncode);
        }

        /// <summary>
        ///  Form表单提交
        /// </summary>
        /// <typeparam name="TParms"></typeparam>
        /// <typeparam name="TReturn"></typeparam>
        /// <param name="request"></param>
        /// <param name="parms"></param>
        /// <param name="files"></param>
        /// <returns></returns>
        public static async Task<TReturn> FormPostAsync<TParms, TReturn>(this HttpWebRequest request, TParms parms, Dictionary<string, byte[]> files = null!)
        {
            var dict = parms?.ToDictionary();
            string strResult = await request.FormPostAsync(dict!, files, Encoding.UTF8);
            return strResult.ChangeType<TReturn>();
        }
        #endregion

        #endregion
    }
}
